package com.xnyzc.lhy.didi.util;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.xnyzc.lhy.common.entity.GouldResult;
import com.xnyzc.lhy.didi.entity.order.OaSysCityInfo;
import com.xnyzc.lhy.didi.entity.param.xiecheng.request.chatered.LocationInfoDTO;
import com.xnyzc.lhy.didi.entity.price.CharterRulesParam;
import com.xnyzc.lhy.didi.entity.price.OaSysBillRuleNewEmbargoMini;
import com.xnyzc.lhy.didi.tongcheng.penum.ETongChengRideType;
import com.xnyzc.lhy.mis.entity.system.NewBillRules;
import com.xnyzc.lhy.mis.entity.system.OaSysBillRuleMini;
import com.xnyzc.lhy.mis.entity.system.RulesParam;
import com.xnyzc.lhy.mis.entity.system.SpecialRulesParam;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

@Slf4j
public class XieChengUtil {
    private static final String DES = "DES";
    private static final String CHARSET = "UTF-8";

    public static String getCallbackSign(String vendorID, String timeStamp, int length, String secrectKey) {
        StringBuffer buffer = new StringBuffer();
        buffer.append(vendorID);
        buffer.append(timeStamp);
        buffer.append(secrectKey);
        buffer.append(length);
        String res = md5(buffer.toString());
        log.info("XC-" + buffer.toString() + "-" + res);
        return res.toLowerCase();
    }

    public static String getSign(String vendorID, String channel, String version, String timeStamp, int length, String secrectKey) {
        StringBuffer buffer = new StringBuffer();
        buffer.append(vendorID);
        buffer.append(version);
        buffer.append(channel);
        buffer.append(timeStamp);
        buffer.append(secrectKey);
        buffer.append(length);
        String res = md5(buffer.toString());
        log.info("XC-" + buffer.toString() + "-" + res);
        return res.toLowerCase();
    }

    public static String getCharteredSign(String vendorID, String version, String timeStamp, int length, String secrectKey) {
        StringBuffer buffer = new StringBuffer();
        buffer.append(vendorID);
        buffer.append(version);
        buffer.append(timeStamp);
        buffer.append(secrectKey);
        buffer.append(length);
        String res = md5(buffer.toString());
        log.info("XC-" + buffer.toString() + "-" + res);
        return res.toLowerCase();
    }

    /**
     * md5 加密
     *
     * @param input
     * @return
     */
    public static String md5(String input) {
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
        }

        md.update(input.getBytes());
        byte byteData[] = md.digest();
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < byteData.length; i++) {
            buffer.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
        }
        return buffer.toString().toUpperCase();
    }

    public static String encodeDES(String key, String string) throws Exception {
        Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), "DES"));
        byte[] bytes = cipher.doFinal(string.getBytes());
        return byteToHex(bytes);
    }

    public static String decodeDES(String key, String string) throws Exception {
        Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), "DES"));
        byte[] bytes = cipher.doFinal(hex2byte(string));
        return new String(bytes, "UTF-8");
    }

    /**
     * byte数组转hex
     *
     * @param bytes
     * @return
     */
    public static String byteToHex(byte[] bytes) {
        String strHex = "";
        StringBuilder sb = new StringBuilder("");
        for (int n = 0; n < bytes.length; n++) {
            strHex = Integer.toHexString(bytes[n] & 0xFF);
            sb.append((strHex.length() == 1) ? "0" + strHex : strHex); // 每个字节由两个字符表示，位数不够，高位补0
        }
        return sb.toString().trim();
    }

    /**
     * 十六进转二进制
     *
     * @param hexStr 待转换16进制字符串
     * @return 二进制字节组
     */
    public static byte[] hex2byte(String hexStr) {
        if (hexStr == null) {
            return null;
        }
        hexStr = hexStr.trim();
        int len = hexStr.length();
        if (len == 0 || len % 2 == 1) {
            return null;
        }
        byte[] digest = new byte[len / 2];
        try {
            for (int i = 0; i < hexStr.length(); i += 2) {
                digest[i / 2] = (byte) Integer.decode("0x" + hexStr.substring(i, i + 2)).intValue();
            }
            return digest;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 携程包车加密参数方法
     *
     * @param encryptStr
     * @param secretKey
     * @return
     * @throws UnsupportedEncodingException
     * @throws InvalidKeyException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     * @throws NoSuchPaddingException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     */
    public static String encryptDES(String encryptStr, String secretKey)
            throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException,
            NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
        SecureRandom random = new SecureRandom();
        byte[] inputByteArray = encryptStr.getBytes(CHARSET);

        byte[] key = secretKey.getBytes(CHARSET);
        DESKeySpec desKey = new DESKeySpec(key);

        // 创建一个密匙工厂，然后用它把DESKeySpec转换成SecretKey对象
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
        SecretKey securekey = keyFactory.generateSecret(desKey);
        // Cipher对象实际完成加密操作
        Cipher cipher = Cipher.getInstance(DES);
        // 用密匙初始化Cipher对象
        cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
        // 现在，获取数据并加密
        // 正式执行加密操作
        byte[] aaaa = cipher.doFinal(inputByteArray);

        StringBuilder sb = new StringBuilder();
        for (byte b : aaaa) {
            Integer i = b & 0xFF;
            sb.append(String.format("%2s", Integer.toHexString(i).toUpperCase()).replace(' ', '0'));
        }

        return sb.toString();
    }

    /**
     * 携程通信解密方法
     *
     * @param secretStr
     * @param secretKey
     * @return
     */
    public static String decrypt(String secretStr, String secretKey) {
        String TRANSFORMATION = "DES/ECB/PKCS5Padding";
        if (StringUtils.isEmpty(secretStr) || StringUtils.isEmpty(secretKey)) {
            return "";
        }
        try {
            byte[] src = hexStringToByte(secretStr.toUpperCase());
            DESKeySpec desKey = new DESKeySpec(secretKey.getBytes("UTF-8"));
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey securekey = keyFactory.generateSecret(desKey);
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.DECRYPT_MODE, securekey);
            byte[] out = cipher.doFinal(src);
            return new String(out, "UTF-8");
        } catch (Exception e) {
            log.error("decrypt error", e);
            return "";
        }
    }

    private static byte[] hexStringToByte(String hex) {
        int len = (hex.length() / 2);
        byte[] result = new byte[len];
        char[] achar = hex.toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            result[i] = (byte) (toByte(achar[pos]) << 4 | (toByte(achar[pos + 1]) & 0xff));
        }
        return result;
    }

    private static byte toByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    /**
     * @param sAdCode 起点城市编码
     * @param eAdCode 终点城市编码
     * @param reMap1  规则数据
     * @return
     */
    public static HashMap<String, Integer> verifyAreaCode(String sAdCode, String eAdCode, List<NewBillRules> reMap1) {
        HashMap<String, Integer> reMap = new HashMap();
        for (int i = 0; i < reMap1.size(); i++) {
            NewBillRules billRules = reMap1.get(i);
            String jsonRules = billRules.getJsonRules();
            CharterRulesParam charterRulesParams = JSON.parseObject(jsonRules, CharterRulesParam.class);
            int veTpe = ETongChengRideType.getById(billRules.getVehicleType()).getValue();
            String ruleName = billRules.getRulesName();
            List<OaSysBillRuleNewEmbargoMini> em = charterRulesParams.getRuleEmbargos();
            for (int j = 0; j < em.size(); j++) {
                OaSysBillRuleNewEmbargoMini embargoMini = em.get(j);
                //判断禁运起点和目的地勾选情况
                int refuseType = embargoMini.getRefuseType();
                int flag;
                if (refuseType == 0) {
                    //起点在其中则禁运
                    flag = 0;
                } else if (refuseType == 1) {
                    //终点禁运
                    flag = 1;
                } else if (refuseType == 2) {  //0 and 1终点禁运
                    // 终点或起点在其中
                    flag = 2;
                } else if (refuseType == 3) {
                    //起点和终点都在其中则禁运
                    flag = 3;
                } else {
                    //默认无禁运
                    flag = 4;
                }
                int areaLevel = embargoMini.getAreaLevel();//地区等 省、市、县区
                boolean verifiedValue = verifyArea(embargoMini.getAreaCode(), sAdCode, eAdCode, areaLevel, flag);
                if (veTpe == 0) {//经济型
                    if (verifiedValue) {//如果判断为true，则说明命中禁运区域
                        reMap.put(veTpe + ruleName, 1);
                        break;
                    } else {
                        reMap.put(veTpe + ruleName, 0);
                    }
                } else if (veTpe == 1) {//舒适性
                    if (verifiedValue) {//如果判断为true，则说明命中禁运区域
                        reMap.put(veTpe + ruleName, 1);
                        break;
                    } else {
                        reMap.put(veTpe + ruleName, 0);
                    }
                } else if (veTpe == 2) {//商务型
                    if (verifiedValue) {//如果判断为true，则说明命中禁运区域
                        reMap.put(veTpe + ruleName, 1);
                        break;
                    } else {
                        reMap.put(veTpe + ruleName, 0);
                    }
                } else if (veTpe == 3) {//豪华型
                    if (verifiedValue) {//如果判断为true，则说明命中禁运区域
                        reMap.put(veTpe + ruleName, 1);
                        break;
                    } else {
                        reMap.put(veTpe + ruleName, 0);
                    }
                }

            }
        }
        return reMap;
    }

    /**
     * @param sAdCode   高德获取的起点adcode
     * @param eAdCode   高德获取的终点adcode
     * @param areaLevel 数据库保存的行政区划等级
     * @param flag      起点终点禁运情况
     * @return
     */
    public static boolean verifyArea(String adcode, String sAdCode, String eAdCode, int areaLevel, int flag) {
        boolean r = false;
        if (flag == 4) { //不禁运直接返回
            return r;
        }
        String al = "";
        if (areaLevel == 0) {//省、直辖市
            //判断行政编吗前两位
            al = adcode.substring(0, 2);
            r = verifyAreaType(al, flag, sAdCode, eAdCode);
        } else if (areaLevel == 1) {//市级
            //市级判断前4位
            al = adcode.substring(0, 4);
            r = verifyAreaType(al, flag, sAdCode, eAdCode);
        } else if (areaLevel == 2) {//区县级
            //区县精确对比
            al = String.valueOf(adcode);
            r = verifyAreaType(al, flag, sAdCode, eAdCode);
        }
        return r;
    }

    public static boolean verifyAreaType(String al, int flag, String sAdCode, String eAdCode) {
        boolean r = false;
        if (flag == 0) {//起点是否在禁运区域
            r = sAdCode.startsWith(al);
        } else if (flag == 1) {//终点是否在禁运区域
            r = eAdCode.startsWith(al);
        } else if (flag == 2) {//起点或终点是否在禁运区域
            r = sAdCode.startsWith(al) || eAdCode.startsWith(al);
        } else if (flag == 3) {//起点和终点是否在禁运区域
            r = sAdCode.startsWith(al) && eAdCode.startsWith(al);
        }
        return r;
    }

    /**
     * 计算距离城市中心点距离
     *
     * @param oaSysCityInfo 城市中心点列表
     * @param sLocation      上车位置
     * @param eLocation      下车位置
     */
    public static BigDecimal centerDistance(OaSysCityInfo oaSysCityInfo, LocationInfoDTO sLocation, LocationInfoDTO eLocation) {
        //如果起点终点在同一个位置
        String[] cityCenterPoints = oaSysCityInfo.getCityCenterPoints().split(";");
        Double sLatitude = sLocation.getLatitude().doubleValue();
        Double sLongitude = sLocation.getLongitude().doubleValue();
        //计算距离中心点最短的
        Double reDistance = 0D, sDistance = 0D, eDistance = 0D;
        for (int i = 0; i < cityCenterPoints.length; i++) {
            String[] tmpStr = cityCenterPoints[i].split(",");
            Double clng = Double.valueOf(tmpStr[0]);
            Double clat = Double.valueOf(tmpStr[1]);
            double tmpDis = getDistance(sLongitude, sLatitude, clng, clat);
            if (sDistance==0D){
                sDistance = tmpDis;
            }
            if (tmpDis < sDistance) {
                //转成千米
                sDistance = tmpDis;
            }
        }
        if (!sLocation.equals(eLocation)) {
            //起点终点不在同一个位置，还要计算终点距离做对比
            Double eLatitude = eLocation.getLatitude().doubleValue();
            Double eLongitude = eLocation.getLongitude().doubleValue();
            for (int i = 0; i < cityCenterPoints.length; i++) {
                String[] tmpStr = cityCenterPoints[i].split(",");
                Double clng = Double.valueOf(tmpStr[0]);
                Double clat = Double.valueOf(tmpStr[1]);
                double tmpDis = getDistance(eLongitude,eLatitude,  clng, clat);
                if (eDistance==0D){
                    eDistance = tmpDis;
                }
                if (tmpDis < eDistance) {
                    //转成千米
                    eDistance = tmpDis;
                }
            }
        }
        //选出起点终点中较大的值返回
        reDistance = Math.max(sDistance, eDistance);
        return new BigDecimal(reDistance/1000);
    }


    /**
     * 距离计算，请参考下面代码
     *
     * @param lng1
     * @param lat1
     * @param lng2
     * @param lat2
     * @return 米
     */
    public static double getDistance(double lng1, double lat1, double lng2, double lat2) {
        double radLat1 = Math.toRadians(lat1);
        double radLat2 = Math.toRadians(lat2);
        double a = radLat1 - radLat2;
        double b = Math.toRadians(lng1) - Math.toRadians(lng2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1)
                * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        s = s * 6378137.0;// 取WGS84标准参考椭球中的地球长半径(单位:m)
        s = Math.round(s * 10000) / 10000;
        return s;
    }

    public static HashMap<String, Object> exceptFee(Integer channel, double time, double mileage, int tolls, Date tripStartTime,
                                                    OaSysBillRuleMini oaSysBillRule, List<SpecialRulesParam> specialTimeRules,
                                                    List<SpecialRulesParam> specialDateRules, String ruleId, Double premium, Integer drawRatio,BigDecimal comboPrice) {
        //里程费
        BigDecimal mileageFee = new BigDecimal(0);
        //处理相减小于0，防止运算为负值
        if (mileage - oaSysBillRule.getStartingMileage().doubleValue() > 0) {
            mileageFee = mileageFee.add(new BigDecimal((mileage - oaSysBillRule.getStartingMileage().doubleValue()) * oaSysBillRule.getMileageFee().doubleValue()));
        }
        HashMap<String, Object> priceMap = new HashMap<>();

        return priceMap;

    }
}
